package com.fujimana.rockincat.restree.util;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import com.fujimana.rockincat.restree.exception.RuntimeInvocationTargetException;

public class ClassUtils {

	public static Class<?> loadClass(String name) {
		FileInputClassLoader classLoader = new FileInputClassLoader();

		try {
			if (new File(name).isFile()) {
				return classLoader.loadClassFile(new File(name));
			} else {
				return classLoader.loadClassFile(name);
			}
		} catch (IOException e) {
			return null;
		} catch (ClassNotFoundException e) {
			return null;
		}

	}

	public static void setField(Object target, String name, Object value) {
		
		Field f = findField(target.getClass(), name);
		
		if(f == null) {
			return;
		}
		
		try {
			f.setAccessible(true);
			f.set(target, value);
			f.setAccessible(false);
		} catch (IllegalArgumentException e) {
			// nothing to do.
		} catch (IllegalAccessException e) {
			// nothing to do.
		}
		
	}
	
	private static Field findField(Class<?> target, String name) {
		if(target == Object.class) {
			return null;
		}
		
		try {
			Field field = target.getDeclaredField(name);
			
			if(field != null) {
				return field;
			}
			
			return findField(target.getSuperclass(), name);
		} catch (SecurityException e) {
			return null;
		} catch (NoSuchFieldException e) {
			return null;
		}
	}

	public static boolean isField(Class<?> target, String name) {
		if(target == Object.class) {
			return false;
		}
		
		try {
			Field field = target.getDeclaredField(name);
			
			if(field != null) {
				return true;
			}
			
			return isField(target.getSuperclass(), name);
		} catch (SecurityException e) {
			return false;
		} catch (NoSuchFieldException e) {
			return false;
		}
		
	}

	public static String filenameToClassname(String filename) {
		return filename.substring(0, filename.lastIndexOf(".class")).replace(
				'/', '.').replace('\\', '.');
	}

	public static Object newInstance(Class<?> clazz) {
		try {
			return clazz.newInstance();
		} catch (InstantiationException e) {
			return null;
		} catch (IllegalAccessException e) {
			return null;
		}
	}

	public static Object invokeMethod(Object o, Method method, Object... args) {

		Object ret = null;
		try {
			ret = method.invoke(o, args);
		} catch (IllegalArgumentException e) {
			throw new RuntimeInvocationTargetException(e);
		} catch (IllegalAccessException e) {
			throw new RuntimeInvocationTargetException(e);
		} catch (InvocationTargetException e) {
			Throwable throwable = e.getCause();
			
			if(RuntimeException.class.isAssignableFrom(throwable.getClass())) {
				throw (RuntimeException)throwable;
			}
			
			throw new RuntimeInvocationTargetException(e.getCause());
		}

		return ret;
	}
}
